package com.zmn.oms.dubbo.impl.zmn.master.discount;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.zmn.common.constant.MemberConsts;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.math.MoneyUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.dms.common.enums.DiscountTypeEnums;
import com.zmn.dms.common.enums.coup.ThirdPlatEnum;
import com.zmn.manager.redis.lock.DistributedLock;
import com.zmn.manager.redis.lock.DistributedLockUtils;
import com.zmn.oms.business.interfaces.discount.OrderDiscountBService;
import com.zmn.oms.business.interfaces.orderamount.OrderAmountCalcBService;
import com.zmn.oms.business.interfaces.work.OrderWorkAmountBService;
import com.zmn.oms.common.constant.LockConsts;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.common.constant.TriggerAmountChangeEnum;
import com.zmn.oms.common.dto.OmsOperator;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.dubbo.dto.common.work.BaseRequestDIO;
import com.zmn.oms.dubbo.dto.common.work.UseTimesCoupDIO;
import com.zmn.oms.dubbo.dto.zmn.discount.CouponDiscountDIO;
import com.zmn.oms.dubbo.dto.zmn.discount.OrderDiscountRefreshDRO;
import com.zmn.oms.dubbo.impl.OmsBaseRemoteService;
import com.zmn.oms.dubbo.interfaces.zmn.master.discount.MasterDiscountRemoteService;
import com.zmn.oms.dubbo.utils.DubboConsts;
import com.zmn.oms.model.bo.orderamount.OrderAmountCalcBO;
import com.zmn.oms.model.bo.orderamount.OrderDiscountCompareBO;
import com.zmn.oms.model.bo.orderamount.ReCalcOrderAmountDIO;
import com.zmn.oms.model.bo.work.discount.UseTimesCoupBO;
import com.zmn.oms.model.dto.work.modify.amount.DiscountCouponDTO;
import com.zmn.oms.model.entity.discount.OrderDiscount;
import com.zmn.oms.model.entity.member.OrderMember;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.vo.work.OperatePermissionVO;
import com.zmn.oms.services.interfaces.discount.OrderDiscountService;
import com.zmn.oms.services.interfaces.member.OrderMemberService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.zmn.business.interfaces.work.ZsOrderWorkOperatePermissionBService;
import com.zmn.oms.zmn.normal.business.interfaces.discount.ZsNormalOrderDiscountBService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 类描述：师傅工单服务
 *
 * @author heciqi
 * @date 2020/03/27 13:47
 */
@Slf4j
@Service(loadbalance = "roundrobin", timeout = 15000, retries = 2, version = DubboConsts.INTERFACE_VERSION, validation = "false")
public class MasterDiscountRemoteServiceImpl extends OmsBaseRemoteService implements MasterDiscountRemoteService {
	private static final String TAG = "啄木鸟-工单优惠";

	@Autowired
	ZsNormalOrderDiscountBService zsNormalOrderDiscountBService;
	@Autowired
	ZsOrderWorkOperatePermissionBService zsOrderWorkOperatePermissionBService;
	@Autowired
	OrderWorkService orderWorkService;
	@Autowired
	OrderMemberService orderMemberService;
	@Autowired
	OrderAmountCalcBService orderAmountCalcBService;
	@Autowired
	OrderDiscountService orderDiscountService;
	@Autowired
	OrderWorkAmountBService orderWorkAmountBService;
	@Autowired
	OrderDiscountBService orderDiscountBService;


	@Override
	public ResponseDTO useCoupon(CouponDiscountDIO couponDiscountDIO) {

		// 转换验券平台
		if (Objects.nonNull(couponDiscountDIO.getThirdType()) && !Objects.equals(couponDiscountDIO.getThirdType(), 30)) {
			if (Objects.equals(com.zmn.market.common.enums.ThirdPlatEnum.KOUBEI_PLAT_TYPE.getCode(), couponDiscountDIO.getThirdType())) {
				couponDiscountDIO.setThirdType(ThirdPlatEnum.THIRD_COUP_TYPE_KB.getKey());
			} else if (Objects.equals(com.zmn.market.common.enums.ThirdPlatEnum.MEITUAN_PLAT_TYPE.getCode(), couponDiscountDIO.getThirdType())) {
				couponDiscountDIO.setThirdType(ThirdPlatEnum.THIRD_COUP_TYPE_MT.getKey());
			}
		}

		// 会员权益是否包含限免权益,若包含则不能使用优惠券。
		Long orderId = couponDiscountDIO.getOrderId();
		log.info("[{}]使用优惠：{}",orderId,JSON.toJSONString(couponDiscountDIO));
		OrderMember orderMember = orderMemberService.findMemberByKey(orderId);
		if (Objects.nonNull(orderMember) && Objects.equals(orderMember.getEquityType(), MemberConsts.EQUITY_FREE)) {
			return ResponseDTO.fail("会员单已使用限免权益，无法与优惠券叠加");
		}

		String couponCode = couponDiscountDIO.getCouponCode();
		Long workId = couponDiscountDIO.getWorkId();

		if (org.apache.commons.lang.StringUtils.isBlank(couponCode) || Objects.isNull(orderId) || Objects.isNull(workId)) {
			logger.error("[{}] 参数错误：orderId : {} couponCode : {}", TAG, orderId, couponCode);
			return ResponseDTO.fail("提交参数错误");
		}

		// 1、校验优惠券是否可用
		OperatePermissionVO operatePermission = zsOrderWorkOperatePermissionBService.getOperatePermission(couponDiscountDIO.getOrderId(), couponDiscountDIO.getWorkId(), OrderConsts.ORDER_OP_TYPE_DISCOUNT_COUPON);
		if (!operatePermission.getCanOperate()) {
			return ResponseDTO.fail(operatePermission.getMsg());
		}

		OrderWork orderWork = orderWorkService.findOrderWorkByKey(couponDiscountDIO.getOrderId(), couponDiscountDIO.getWorkId());
		if (orderWork == null) {
			return ResponseDTO.fail("工单不存在");
		}

		boolean canDiscount = false;
		DiscountCouponDTO couponDTO = new DiscountCouponDTO();
		this.setLogParam(couponDiscountDIO, couponDTO);
		couponDTO.setThirdType(couponDiscountDIO.getThirdType());
		// 计算和更新工单金额
		ReCalcOrderAmountDIO calcOrderAmountDIO = orderAmountCalcBService.getReCalcOrderAmountDIO(orderWork);
		calcOrderAmountDIO.setInvoker(2);
		calcOrderAmountDIO.setCouponCode(couponDiscountDIO.getCouponCode());
		calcOrderAmountDIO.setThirdType(couponDiscountDIO.getThirdType());
		// 外部店铺ID
		if(StringUtil.isNotBlank(couponDiscountDIO.getExternalShopId())){
			calcOrderAmountDIO.setExternalShopId(couponDiscountDIO.getExternalShopId());
		}
		// 店铺电话
		if(StringUtil.isNotBlank(couponDiscountDIO.getCalledNumber())){
			calcOrderAmountDIO.setCalledNumber(couponDiscountDIO.getCalledNumber());
		}

		try {
			OrderAmountCalcBO orderAmountCalcBO = orderAmountCalcBService.reCalcOrderAmountAndDiscountAmount(TriggerAmountChangeEnum.VALIDATE_COUPON, calcOrderAmountDIO, couponDiscountDIO.getForceVerify());
			if (orderAmountCalcBO.getOrderDiscountCalcBO() != null) {
				List<OrderDiscount> orderDiscountList = orderAmountCalcBO.getOrderDiscountCalcBO().getOrderDiscountList();
				// 外部券
				List<OrderDiscount> couponDiscounts = orderDiscountList.stream()
						.filter(e -> Objects.equals(e.getThirdCode(), GlobalConsts.YES))
						.collect(Collectors.toList());
				if (CollectionUtil.isNotNullOrEmpty(couponDiscounts)) {
					canDiscount = true;
				}
				// 内部券
				else {
					couponDiscounts = orderDiscountList.stream()
							.filter(e -> Objects.equals(e.getRedeemCode(), couponCode))
							.collect(Collectors.toList());
					if (CollectionUtil.isNotNullOrEmpty(couponDiscounts)) {
						canDiscount = true;
					}
				}
				if (canDiscount) {
					OrderDiscount orderDiscount = couponDiscounts.get(0);
					couponDTO.setAmount(orderDiscount.getAmount());
					couponDTO.setItemCode(couponCode);
					couponDTO.setType(orderDiscount.getType());
					couponDTO.setOrderAmountCalcBO(orderAmountCalcBO);
					zsNormalOrderDiscountBService.saveCoupon(couponDTO);
				}
			}
		} catch (OmsBaseException e) {
			Integer thirdPlatEnum = couponDTO.getThirdType() != null ? couponDTO.getThirdType() : ThirdPlatEnum.THIRD_COUP_TYPE_OTHER.getKey();
			couponDTO.setRemark(String.format("%s优惠券：%s，%s",ThirdPlatEnum.getValue(thirdPlatEnum),couponCode, org.apache.commons.lang.StringUtils.defaultIfBlank(e.getMessage(), "优惠券使用失败-未知原因")));
			zsNormalOrderDiscountBService.saveFailCoupon(couponDTO);
			return ResponseDTO.fail(e.getCode(), e.getMessage());
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return ResponseDTO.fail(e.getMessage());
		}

		if (canDiscount) {
			return ResponseDTO.success("用券成功，使用1张，总优惠金额 " + MoneyUtil.parseToYuanEndWithUnit(couponDTO.getAmount()));
		} else {
			return ResponseDTO.fail("未返回优惠信息");
		}
	}

	/**
	 * 使用最新优惠（刷新获取最新优惠）
	 *
	 * @param baseRequestDIO
	 */
	@Override
	public ResponseDTO useNewDiscount(BaseRequestDIO baseRequestDIO) {
		log.info("工程师获取最新优惠入参：{}", JSON.toJSONString(baseRequestDIO));
		String lockKey = String.format("%s", baseRequestDIO.getOrderId());
		DistributedLock lock = DistributedLockUtils.build(LockConsts.LOCK_ORDER_AMOUNT + lockKey, LockConsts.LOCK_VALID_TIME);

		try {
			if (lock.tryLock()) {
				OmsOperator operator = new OmsOperator();
				operator.setOrderId(baseRequestDIO.getOrderId());
				operator.setWorkId(baseRequestDIO.getWorkId());
				orderDiscountBService.refreshOrderDiscount(operator);
			}

			return ResponseDTO.success();
		} catch (OmsBaseException e) {
			log.error(e.getMessage(), e);
			return ResponseDTO.fail(e.getMessage());
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return ResponseDTO.fail("使用最新优惠-异常");
		} finally {
			lock.unlock();
		}
	}

	@Override
	public ResponseDTO<OrderDiscountRefreshDRO> refreshOrderDiscount(BaseRequestDIO dio) {
		log.info("工程师获取最新优惠入参：{}", JSON.toJSONString(dio));
		String lockKey = String.format("%s", dio.getOrderId());
		DistributedLock lock = DistributedLockUtils.build(LockConsts.LOCK_ORDER_AMOUNT + lockKey, LockConsts.LOCK_VALID_TIME);

		try {
			OrderDiscountCompareBO compareBO = new OrderDiscountCompareBO();
			if (lock.tryLock()) {
				OmsOperator operator = new OmsOperator();
				operator.setOrderId(dio.getOrderId());
				operator.setWorkId(dio.getWorkId());
				compareBO = orderDiscountBService.refreshOrderDiscount(operator);
			}

			OrderDiscountRefreshDRO discountRefreshDRO = new OrderDiscountRefreshDRO();

			// 过滤出优惠券和代金券优惠
			List<OrderDiscount> oldDiscountList = Optional.ofNullable(compareBO.getOldDiscountList())
					.orElse(Lists.newArrayList())
					.stream()
					.collect(Collectors.toList());
			List<OrderDiscount> newDiscountList = Optional.ofNullable(compareBO.getNewDiscountList())
					.orElse(Lists.newArrayList())
					.stream()
					.collect(Collectors.toList());


			Integer oldDiscountAmount = oldDiscountList.stream().mapToInt(OrderDiscount::getAmount).sum();

			if (CollectionUtil.isNullOrEmpty(newDiscountList)) {
				// 新优惠信息为空
				discountRefreshDRO.setChangeStatus(GlobalConsts.NONE);
				discountRefreshDRO.setDiscountAmount(0);
				discountRefreshDRO.setCoupDiscountAmount(0);

				// 从老的优惠获取相关信息
				if (CollectionUtil.isNotNullOrEmpty(oldDiscountList)) {
					discountRefreshDRO.setDiscountAmount(oldDiscountAmount);

					Integer coupDiscountAmount = getCoupDiscountAmount(oldDiscountList);
					discountRefreshDRO.setCoupDiscountAmount(coupDiscountAmount);
				}

			} else {

				// 优惠金额
				Integer newDiscountAmount = newDiscountList.stream().mapToInt(OrderDiscount::getAmount).sum();
				discountRefreshDRO.setDiscountAmount(newDiscountAmount);

				// 优惠券优惠金额
				Integer coupDiscountAmount = getCoupDiscountAmount(newDiscountList);
				discountRefreshDRO.setCoupDiscountAmount(coupDiscountAmount);

				// 是否改变
				if (oldDiscountAmount == 0 && newDiscountAmount > oldDiscountAmount) {
					discountRefreshDRO.setChangeStatus(GlobalConsts.NO);
					// 未改变
					String discountMsg = "<span style=\"font-family:&quot;font-size:16px;color:#FB605D;\">系统查询到更佳优惠出现，将自动使用最新优惠，预计优惠</span><span style=\"font-size:16px;font-family:&quot;font-weight:700;color:#E56600;\">"+ MoneyUtil.parseToYuanStr(newDiscountAmount) +"</span><span style=\"font-family:&quot;font-size:16px;color:#555555;\">元</span><span></span>";
					discountRefreshDRO.setDiscountMsg(discountMsg);
				} else if (oldDiscountAmount > 0 && newDiscountAmount > oldDiscountAmount) {
					discountRefreshDRO.setChangeStatus(GlobalConsts.YES);
					// 未改变
					String discountMsg = "<span style=\"font-family:&quot;font-size:16px;color:#FB605D;\">系统查询到可用优惠，将自动使用，预计优惠</span><span style=\"font-size:16px;font-family:&quot;font-weight:700;color:#E56600;\">"+ MoneyUtil.parseToYuanStr(newDiscountAmount) +"</span><span style=\"font-family:&quot;font-size:16px;color:#555555;\">元</span><span></span>";
					discountRefreshDRO.setDiscountMsg(discountMsg);
				}
			}

			return ResponseDTO.success(discountRefreshDRO);
		} catch (OmsBaseException e) {
			log.error(e.getMessage(), e);
			return ResponseDTO.fail(e.getMessage());
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return ResponseDTO.fail("使用最新优惠-异常");
		} finally {
			lock.unlock();
		}
	}

	private Integer getCoupDiscountAmount(List<OrderDiscount> discountList) {
		if (CollectionUtil.isNullOrEmpty(discountList)) {
			return 0;
		}
		return discountList.stream()
				.filter(item -> Objects.equals(item.getCateg(), DiscountTypeEnums.DISCOUNT_COUP_COMMON.getSubType())
						|| Objects.equals(item.getCateg(), DiscountTypeEnums.DISCOUNT_COUP_VOUCHER.getSubType())
						|| Objects.equals(item.getCateg(), DiscountTypeEnums.DISCOUNT_COUP_CASH.getSubType()) )
				.mapToInt(OrderDiscount::getAmount).sum();
	}

	/**
	 * 使用最新优惠（刷新获取最新优惠）
	 *
	 * @param dio
	 */
	@Override
	public ResponseDTO useTimesDiscount(UseTimesCoupDIO dio) {
		log.info("工程师使用次卡入参：{}", JSON.toJSONString(dio));
		String lockKey = String.format("%s", dio.getOrderId());
		DistributedLock lock = DistributedLockUtils.build(LockConsts.LOCK_ORDER_AMOUNT + lockKey, LockConsts.LOCK_VALID_TIME);

		try {
			if (lock.tryLock()) {
				zsNormalOrderDiscountBService.useTimesDiscount(BeanMapper.map(dio, UseTimesCoupBO.class));
			}
			return ResponseDTO.success();
		} catch (OmsBaseException e) {
			log.error(e.getMessage(), e);
			return ResponseDTO.fail(e.getMessage());
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return ResponseDTO.fail("使用次卡优惠-异常");
		} finally {
			lock.unlock();
		}
	}
}
